﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace LaTeXGrapher
{
    public class FunctionData
    {
        public string Name { get; private set; }

        List<string> _arguments = new List<string>();
        List<KeyValuePair<string, string>> _expressions = new List<KeyValuePair<string, string>>(); // [(expr,cond)]
        List<string> _special = new List<string>();

        public IEnumerable<KeyValuePair<string, string>> Expressions { get { return _expressions.AsReadOnly(); } }
        public IEnumerable<string> Arguments { get { return _arguments.AsReadOnly(); } }

        public FunctionData(string name, IEnumerable<string> arguments, IEnumerable<KeyValuePair<string, string>> expressions, IEnumerable<string> special)
        {
            Name = name;

            _arguments.AddRange(arguments);
            _expressions.AddRange(expressions);
            _special.AddRange(special);
        }

        public IFunction2d LoadContext(FunctionContext context)
        {
            if (context.ContainsIFunction2d(Name))
                return context.GetIFunction2d(Name);
            Func<double, double> f = (Func<double, double>)context.LookupF(Name);
            IFunction2d func = new DynamicFunction(
                Name, 
                f, 
                context.EvaluateSpecial(_special), 
                context);
            context.AddIFunction2d(Name, func);
            return func;
        }
    }

    class DynamicFunction : IFunction2d
    {
        public string Name { get; private set; }

        Func<double, double> _function;
        IEnumerable<double> _special;
        FunctionContext _context;

        public DynamicFunction(string name, Func<double, double> function, IEnumerable<double> special, FunctionContext context)
        {
            Name = name;
            _function = function;
            _special = special;
            _context = context;
        }

        #region IFunction2d Members

        public System.Windows.Point Min
        {
            get { return _context.Min; }
        }

        public System.Windows.Point Max
        {
            get { return _context.Max; }
        }

        public IEnumerable<double> SpecialPoints
        {
            get { return _special; }
        }

        public System.Windows.Vector TickInterval
        {
            get { return _context.TickInterval; }
        }

        public System.Windows.Vector? MarkTick(bool bX, double t, double tickWidth)
        {
            return _context.MarkTick(bX, t, tickWidth);
        }

        public double Function(double x)
        {
            return _function(x);
        }

        #endregion
    }
}
